package com.example.demo.netty.websocket;

import com.example.demo.netty.websocket.proto.ProtobufInfo;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.nio.charset.StandardCharsets;

// 这里的泛型要给BinaryWebSocketFrame来处理二进制帧
public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<BinaryWebSocketFrame> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, BinaryWebSocketFrame binaryWebSocketFrame) throws Exception {

        // content将二进制帧的全部内容以ByteBuf的形式返回,然后nioBuffer将其转换为需要的ByteBuffer
        // parseFrom将ByteBuffer解析为 ProtobufInfo.ClassInfo 对象（它也接受直接的一个字节数组）
        // 然后用fireChannelRead方法将它传给后续的业务处理器
        // 注意这里不能使用array(),因为这里binaryWebSocketFrame.content()得到的是堆外内存中的数据
        // 而对外内存数据操作时不可以直接转为字节数组,所以用nioBuffer来直接操作堆外内存
        // Netty会管理nioBuffer返回的堆外内存对象,不用担心安全问题。
        ctx.fireChannelRead(ProtobufInfo.ClassInfo.parseFrom
                (binaryWebSocketFrame.content().nioBuffer()));// 传给下一个处理器

        // 构建一个对象，发给前端
        ProtobufInfo.ClassInfo data = ProtobufInfo.ClassInfo.newBuilder()
                // 这里设置对象具体是枚举类中的谁，括号里就很直白，跟进去看proto文件就很清晰
                .setDataEnum(ProtobufInfo.ClassInfo.ClassType.User)
                // 这里用上面设置对象对应的set方法传入自己的构建器
                .setUser(ProtobufInfo.User.newBuilder()
                // 设置对应的属性并创建
                .setAge(28).setName("asd").build()).build();

        // 先将data用toByteArray转为一个字节数组,然后由Unpooled.wrappedBuffer转为ByteBuf
        // 再把它作为参数给BinaryWebSocketFrame创建一个二进制帧类,不然websocket无法传输,最后发出去
        ctx.writeAndFlush(new BinaryWebSocketFrame(Unpooled.wrappedBuffer(data.toByteArray())));

    }


    /**
     * 当channel连接成功之后被加入ChannelPipeline时调用
     * 此时连接还未建立成功，一般用于初始化资源
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
//        System.out.println("初始化资源");
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 打印id唯一值
        System.out.println("连接已建立"+ctx.channel().id().asLongText());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        System.out.println("连接断开");
        super.handlerRemoved(ctx); // 执行默认移除操作
    }
}
